import { IColor, ITriggerEvent, ModelComponent, Vec3, log, native, physics, utils } from 'cc';
import { _decorator, BoxCollider, Collider, ColliderComponent, Component, ICollisionEvent, Node } from 'cc';
import { Ball } from './../billiards/Ball';
import EventManager from '../../tools/EventManager';
import { App } from '../../App';
import { find } from 'cc';
import UtilTool from '../../tools/UtilTool';
import { input } from 'cc';
import { Input } from 'cc';
import { EventTouch } from 'cc';
import { EventConst } from '../../common/Common';
import { BoxCollider2D } from 'cc';
import { Rect } from 'cc';
import { Vec2 } from 'cc';
import { GameBaseModel } from './../billiards/GameBaseModel';
import { Role } from './../billiards/Role';
import { tween } from 'cc';
import { Tween } from 'cc';
import { SpriteFrame } from 'cc';
import { Prefab } from 'cc';
import { instantiate } from 'cc';
import { BALL_RADIUS } from './GameManage';

let POS_Y = 10

let OFFEST_X = 17// 与手的偏移量
let OFFEST_Z = -10.8 // 与手的偏移量

enum PosBallState {
    OUT_DESK = 0, // 桌面范围外
    IN_DESK = 1, // 桌面范围内
    CAN_POS = 2, // 可以放置
}

const { ccclass, property } = _decorator;

@ccclass('PosBall')
export class PosBall extends Component {

    @property(Prefab)
    posTipPrefab : Prefab = null 

    posTipNode : Node = null // 摆球手势图片

    isPosBall : boolean = false

    posWhiteRect : Rect = null // 摆球区域

    gameView : GameBaseModel = null

    isMine : boolean = false

    // 可以放置球的所有的点的列表
    public ballPosList : Vec3[] = []

    start() {
        
        this.gameView = App.Model.gameView as GameBaseModel

        input.on(Input.EventType.TOUCH_START, this.onTouchStart, this)
        input.on(Input.EventType.TOUCH_MOVE, this.onTouchMove, this)
        input.on(Input.EventType.TOUCH_END, this.onTouchEnd, this)

        // 初始化摆球区域
        let wallList = []
        this.gameView.desk.children.forEach((item) => {
            if(item.name == "wall") {
                wallList.push(item)
            }
        })
            
        let radius = this.gameView.whiteBall.getComponent(Ball).getSize() / 2
        let xMax = wallList[0].worldPosition.x - wallList[0].scale.x / 2 - radius
        let xMin = wallList[5].worldPosition.x + wallList[5].scale.x / 2 + radius
        let zMin = wallList[1].worldPosition.z + wallList[1].scale.x / 2 + radius
        let zMax = wallList[2].worldPosition.z - wallList[2].scale.x / 2 - radius
        this.posWhiteRect = new Rect(zMin, xMin, Math.abs(zMax - zMin), Math.abs(xMax - xMin))

        App.Event.on(EventConst.POS_WHITE_BALL, this.showPos, this)

        // test
        // this.isPosBall = true

        let interval = BALL_RADIUS*2
        let xLength = Math.abs(zMax - zMin)
        let yLength = Math.abs(xMax - xMin)
        let stepX = Math.floor(xLength / interval)
        let stepY = Math.floor(yLength / interval)
        for(let i=0; i<stepX; i++) {
            for(let j=0; j<stepY; j++) {
                let x = zMin + interval * i
                let y = xMin + interval * j
                const posVec3 = new Vec3(y, POS_Y, x)
                this.ballPosList.push(posVec3)
            }
        }

        this.posTipNode = instantiate(this.posTipPrefab)
        this.posTipNode.parent = this.gameView.gameLayer

        this.reset()
    }

    reset() {
        this.hide()
        Tween.stopAllByTarget(this)
        Tween.stopAllByTarget(this.node)
    }

    // 等待摆球
    showPos(isMine=true) {

        this.isMine = isMine

        this.isPosBall = true
        this.node.active = true

        this.setBallPos(new Vec3(-25, this.node.worldPosition.y, 3))
        this.setBallState(PosBallState.CAN_POS)
    }

    // 球设置到场外
    hide() {
        this.isPosBall = false
        let outWorldPos = new Vec3(10000, this.node.worldPosition.y, 10000)
        this.setBallPos(outWorldPos)
    }

    onTouchStart(event: EventTouch) : void {
        if(!this.isPosBall || !this.isMine) {
            return
        }

        let worldPos = this.get3dWorldPosFromUI(event.getLocation())
        this.setBallPos(new Vec3(worldPos.x, this.node.worldPosition.y, worldPos.z))

        let isInDesk = this.checkIsInDesk(this.node.worldPosition)
        if(isInDesk) {
            let isRangle = this.checkPosIsInRange(this.node.worldPosition)
            if(isRangle) {
                this.setBallState(PosBallState.CAN_POS)
            } else {
                this.setBallState(PosBallState.IN_DESK)
            }
        } else {
            this.setBallState(PosBallState.OUT_DESK)
        }   

    }

    onTouchMove(event: EventTouch) : void {
        if(!this.isPosBall || !this.isMine) {
            return
        }

        let worldPos = this.get3dWorldPosFromUI(event.getLocation())
        this.setBallPos(new Vec3(worldPos.x, this.node.worldPosition.y, worldPos.z))

        let isInDesk = this.checkIsInDesk(this.node.worldPosition)
        if(isInDesk) {
            let isRangle = this.checkPosIsInRange(this.node.worldPosition)
            if(isRangle) {
                this.setBallState(PosBallState.CAN_POS)
            } else {
                this.setBallState(PosBallState.IN_DESK)
            }
        } else {
            this.setBallState(PosBallState.OUT_DESK)
        }

    }

    onTouchEnd(event: EventTouch) : void {
        if(!this.isPosBall || !this.isMine) {
            return
        }

        let worldPos = this.get3dWorldPosFromUI(event.getLocation())
        this.setBallPos(new Vec3(worldPos.x, this.node.worldPosition.y, worldPos.z))

        let isInDesk = this.checkIsInDesk(this.node.worldPosition)
        if(isInDesk) {
            let isRangle = this.checkPosIsInRange(this.node.worldPosition)
            if(isRangle) {
                this.setBallState(PosBallState.CAN_POS)
                App.Event.emit(EventConst.POS_WHITE_BALL_END, this.node.worldPosition)
                this.hide()
            } else {
                this.setBallState(PosBallState.IN_DESK)
            }
        } else {
            this.setBallState(PosBallState.OUT_DESK)
        }
        
    }

    // 获取UI对应的3d世界坐标
    get3dWorldPosFromUI(uiPos : Vec2) : Vec3 {
        let worldPos = (App.Model.gameView as GameBaseModel).screenToWorld(uiPos)

        UtilTool.printLog("worldPos == ", worldPos.toString())

        return new Vec3(worldPos.x, 0, worldPos.z)
    }

    // 判断球是否在桌面范围内
    checkIsInDesk(worldPos : Vec3) : boolean {
        let curPos = new Vec2(worldPos.z, worldPos.x)
        return this.posWhiteRect.contains(curPos)
    }

    // 判断球是否在可以放置的范围内
    checkPosIsInRange(worldPos : Vec3) : boolean {

        let curPos = new Vec2(worldPos.z, worldPos.x)

        // return false

        let getRadius = (item : Node) => {
            let ballCtrl = item.getComponent(Ball)
            let roleCtrl = item.getComponent(Role)  

            if(ballCtrl) {
                return ballCtrl.getSize() / 2
            }

            if(roleCtrl) {
                return roleCtrl.getSize() / 2
            }

            console.error("can not get node size")

            return 0
        }

        if(this.checkIsInDesk(worldPos)) {
            let ballList = App.Model.gameManage.otherBallArr.filter((item) => {
                return item.active == true
            })

            let whiteBallRadius = getRadius(this.gameView.whiteBall)
            let roleList = (App.Model.gameView as GameBaseModel).roleNodeList

            // 是否在球的范围内，判断两点之间的距离是否少于球的半径
            let checkList = ballList.concat(roleList)
            let isInBallRangle = false
            for(let i=0; i<checkList.length; i++) {
                let item = checkList[i]
                let radius = getRadius(item)
                let pos : Vec2 = new Vec2(item.worldPosition.z, item.worldPosition.x)
                if(UtilTool.subVector2(pos, curPos).length() <= radius + whiteBallRadius) {
                    isInBallRangle = true
                    break
                }
            }
            if(!isInBallRangle) {
                return true
            }

        }

        return false
    }

    // 设置球的状态
    setBallState(ballState) {
        let material = find("model", this.node).getComponent(ModelComponent).getMaterial(0)

        switch(ballState) {
            case PosBallState.OUT_DESK:
                material.setProperty("opacity", 0)
                break
            case PosBallState.IN_DESK:
                material.setProperty("opacity", 0.3)
                break

            case PosBallState.CAN_POS:
                material.setProperty("opacity", 0.8)
                break
        }
    }

    setBallPos(worldPos : Vec3) {

        this.node.worldPosition = new Vec3(worldPos.x+OFFEST_X, worldPos.y, worldPos.z+OFFEST_Z)

        let uiPos = (App.Model.gameView as GameBaseModel).World3DToUI(worldPos)
        this.posTipNode.position = new Vec3(uiPos.x, uiPos.y, 0)
        
    }

    // 设置白球位置
    setWhiteBallPos(pos : Vec3) {

        tween().target(this.node).delay(0.5).call(()=>{
            // 最终设置的球和传入的pos是一样的
            this.setBallPos(new Vec3(pos.x-OFFEST_X, this.node.worldPosition.y, pos.z-OFFEST_Z))
            this.setBallState(PosBallState.CAN_POS)
        }).delay(0.5).call(() => {
            App.Event.emit(EventConst.POS_WHITE_BALL_END, this.node.worldPosition)
            this.hide()
        }).start()
        
    }

}

